package com.sailing.xjpb.orm.query.impl;

import com.google.common.base.CaseFormat;
import com.sailing.xjpb.common.SailingAssert;
import com.sailing.xjpb.common.SailingReflectionUtils;
import com.sailing.xjpb.orm.query.ConditionUnit;
import com.sailing.xjpb.orm.query.QueryCondition;
import com.sailing.xjpb.orm.query.annotation.Condition;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 动态查询条件处理类，完成SQL解析封装、分页条件封装、动态查询条件封装功能。
 *
 * @author YaoWei
 * createTime 2015年7月2日 下午5:09:01
 */
public abstract class QueryConditionImpl implements QueryCondition {

    /**
     * 查询单元
     */
    private final List<ConditionUnit> conditionUnits = new ArrayList<>();

    /**
     * 得到需要查询SQL语句
     */
    protected abstract String getQuery();

    @Override
    public String getQuerySql() {
        this.init();
        String query = getQuery();
        SailingAssert.hasText(query, "主查询语句不能为空！");
        StringBuilder querySql = new StringBuilder(query);
        // 构建查询条件
        for (ConditionUnit unit : conditionUnits) {
            querySql.append(unit.getConditions());
        }
        // 构建group by
        String groupBy = groupBy();
        if (StringUtils.isNotBlank(groupBy)) {
            querySql.append(" ").append(groupBy);
        }
        // 构建order by
        String orderBy = orderBy();
        if (StringUtils.isNotBlank(orderBy)) {
            querySql.append(" ").append(orderBy);
        }
        return querySql.toString().replaceAll("(?i)where\\s+1\\s*=\\s*1and", "where ");
    }

    @Override
    public Map<String, Object> getParameters() {
        this.init();
        Map<String, Object> params = new HashMap<>();
        for (ConditionUnit unit : conditionUnits) {
            params.putAll(unit.getParams());
        }
        return params;
    }

    /**
     * 业务查询参数
     */
    public abstract Object getQueryConditionObj();

    /**
     * 得到SQL中的order条件部分
     */
    public abstract String orderBy();

    /**
     * 得到SQL中的group by条件部分
     */
    public abstract String groupBy();

    /**
     * 添加自定义复杂的查询条件
     */
    public abstract List<ConditionUnit> userConditionUint();

    /**
     * 初始化查询条件
     */
    private void init() {
        if (!conditionUnits.isEmpty()) {
            return;
        }
        convertQueryCondition();
        List<ConditionUnit> userConditionUnits = userConditionUint();
        if (CollectionUtils.isNotEmpty(userConditionUnits)) {
            this.conditionUnits.addAll(userConditionUnits);
        }
        Collections.sort(this.conditionUnits);
    }

    /**
     * 查询条件转换器，将前台传来的查询条件按照一定的规则解析为SQL查询条件
     *
     * @Title: convertQueryCondition
     * @author YaoWei
     */
    private void convertQueryCondition() {
        try {
            Object queryConditionObj = this.getQueryConditionObj();
            if (queryConditionObj == null) {
                return;
            }
            Class<?> clazz = queryConditionObj.getClass();
            List<Field> fields = SailingReflectionUtils.getDeclaredFields(clazz,
                    field -> field.getAnnotation(Condition.class) != null);
            for (Field field : fields) {
                Object fieldValue = SailingReflectionUtils.getField(field, queryConditionObj);
                Condition condition = field.getAnnotation(Condition.class);
                String columnName = this.getColumnName(field);
                boolean notNullValue = !isEmpty(fieldValue);

                ConditionUnit conditionUnit = null;
                String paramKey = field.getName();
                if (notNullValue) {
                    conditionUnit = condition.type().getConditionUnit(columnName, paramKey, fieldValue);
                } else if (!condition.ignoreNull()) {
                    // 生成 xxx is null 类型的sql条件
                    StringBuilder conditionSql = new StringBuilder();
                    conditionSql.append(" and ").append(columnName).append(" is null ");
                    conditionUnit = ConditionUnit.of(conditionSql);
                }

                if (conditionUnit != null) {
                    conditionUnits.add(conditionUnit);
                }
            }
        } catch (Exception e) {
            throw new com.sailing.xjpb.orm.query.SqlParseException("转换sql查询条件过程中出现错误", e);
        }
    }

    /**
     * 根据字段信息获取字段生成的sql查询字段部分 如：字段xxx---> a.xxx
     *
     * @param field 字段信息
     */
    private String getColumnName(Field field) {
        Condition condition = field.getAnnotation(Condition.class);
        StringBuilder sql = new StringBuilder();
        // 获取表别名
        String tabAis = condition.tabAis();
        if (StringUtils.isNotBlank(tabAis)) {
            sql.append(tabAis).append(".");
        }
        // 获取列名
        String columnAis = condition.columnAis();
        if (StringUtils.isNotBlank(columnAis)) {
            sql.append(columnAis);
        } else {
            String columnName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName());
            sql.append(columnName);
        }
        return sql.toString();
    }

    /**
     * 判断是否是空值
     *
     * @param fieldValue 字段值
     */
    private boolean isEmpty(Object fieldValue) {
        if (fieldValue == null) {
            return true;
        }
        if (fieldValue instanceof Character || fieldValue instanceof String) {
            return StringUtils.isBlank(String.valueOf(fieldValue));
        }
        if (fieldValue instanceof Collection) {
            return CollectionUtils.isEmpty((Collection<?>) fieldValue);
        }
        return false;
    }

}
